import pandas as pd
import glob, folium, branca, json
import numpy as np
import matplotlib.pyplot as plt
import holoviews as hv
import panel as pn
import panel.widgets as pnw
hv.extension('bokeh')
/opt/anaconda3/lib/python3.7/site-packages/pandas/compat/_optional.py:138: UserWarning: Pandas requires version '2.7.0' or newer of 'numexpr' (version '2.6.9' currently installed). warnings.warn(msg, UserWarning)
from bokeh.themes.theme import Theme
theme = Theme(
json={
'attrs' : {
'Figure' : {
'background_fill_color': '#535353',
'border_fill_color': '#535353',
'outline_line_color': '#444444',
},
'Grid': {
'grid_line_dash': [6, 4],
'grid_line_alpha': .3,
},
'Axis': {
'major_label_text_color': 'white',
'axis_label_text_color': 'white',
'major_tick_line_color': 'white',
'minor_tick_line_color': 'white',
'axis_line_color': "white"
}
}
})
hv.renderer('bokeh').theme = theme
print(np.datetime64('now'))
2022-09-08T13:57:52
# PUT EVERY COUNTRY REPORTS IN ONE DATAFRAME
files = glob.glob('data/install*country.csv')
files.sort()
ds=pd.DataFrame()
for f in files:
ds = pd.concat([ds,pd.read_csv(f,encoding = 'utf-16')])
ds = ds.reset_index()
ds = ds.drop(columns=['index','Daily Device Upgrades','Total User Installs','Active Device Installs','Install events','Update events','Uninstall events'])
ds['Date']=pd.DatetimeIndex(ds['Date'])
ds['WO-ui']=ds['Daily User Installs'].cumsum()
ds['WO-di']=ds['Daily Device Installs'].cumsum()
ds['WO-uu']=ds['Daily User Uninstalls'].cumsum()
ds['WO-du']=ds['Daily Device Uninstalls'].cumsum()
countries = np.unique(ds['Country'][~ds['Country'].isna()])
for country in np.unique(ds['Country'][~ds['Country'].isna()]):
ds[country+'-di']=ds[ds['Country']==country]['Daily Device Installs'].cumsum()
ds[country+'-ui']=ds[ds['Country']==country]['Daily User Installs'].cumsum()
ds[country+'-du']=ds[ds['Country']==country]['Daily Device Uninstalls'].cumsum()
ds[country+'-uu']=ds[ds['Country']==country]['Daily User Uninstalls'].cumsum()
ds = ds.fillna(method='ffill')
ds = ds.fillna(0)
ds.tail()
| Date | Package Name | Country | Daily Device Installs | Daily Device Uninstalls | Daily User Installs | Daily User Uninstalls | WO-ui | WO-di | WO-uu | ... | UZ-du | UZ-uu | VE-di | VE-ui | VE-du | VE-uu | ZA-di | ZA-ui | ZA-du | ZA-uu | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 11715 | 2022-09-05 | com.kb.android.argo | PA | 0 | 0 | 0 | 0 | 190 | 212 | 138 | ... | 0.0 | 1.0 | 4.0 | 4.0 | 0.0 | 5.0 | 1.0 | 1.0 | 0.0 | 0.0 |
| 11716 | 2022-09-05 | com.kb.android.argo | RU | 0 | 0 | 0 | 0 | 190 | 212 | 138 | ... | 0.0 | 1.0 | 4.0 | 4.0 | 0.0 | 5.0 | 1.0 | 1.0 | 0.0 | 0.0 |
| 11717 | 2022-09-05 | com.kb.android.argo | TR | 0 | 0 | 0 | 0 | 190 | 212 | 138 | ... | 0.0 | 1.0 | 4.0 | 4.0 | 0.0 | 5.0 | 1.0 | 1.0 | 0.0 | 0.0 |
| 11718 | 2022-09-05 | com.kb.android.argo | US | 0 | 0 | 0 | 0 | 190 | 212 | 138 | ... | 0.0 | 1.0 | 4.0 | 4.0 | 0.0 | 5.0 | 1.0 | 1.0 | 0.0 | 0.0 |
| 11719 | 2022-09-05 | com.kb.android.argo | ZA | 0 | 0 | 0 | 0 | 190 | 212 | 138 | ... | 0.0 | 1.0 | 4.0 | 4.0 | 0.0 | 5.0 | 1.0 | 1.0 | 0.0 | 0.0 |
5 rows × 275 columns
A2 = pd.read_csv('A2codes.csv',index_col=1)
A2i = pd.read_csv('A2codes.csv',index_col=0)
labels = sorted([A2['Name'][x] for x in np.hstack([countries,'WO'])])
label = pnw.Select(name='Country', value='World', options=labels)
ptype = pnw.Select(name='Type', value='Install', options=['Install','Uninstall'])
@pn.depends(label.param.value,ptype.param.value)
def create_figure(label,ptype):
code = A2i['Code'][label]
if code != 'WO':
dsi = ds[ds['Country']==code]
else:
dsi=ds
hv_data = hv.Table(dsi, ['Date'])
p1 = hv_data.to.curve(['Date'], [code+'-u'+ptype[0].lower()],label='Users').opts(color='#2acaea')
p2 = hv_data.to.curve(['Date'], [code+'-d'+ptype[0].lower()],label='Devices').opts(color='#d71e3e')
p = p1*p2
p.opts(hv.opts.Curve(width=700, height=400,show_grid=True),
hv.opts.Overlay(legend_position='top_left'))
return p
#Panel dataframe looks better than holoview's
@pn.depends(label.param.value,ptype.param.value)
def create_table(label,ptype):
code = A2i['Code'][label]
if code != 'WO':
dsi = ds[ds['Country']==code]
else:
dsi=ds
return pnw.DataFrame(dsi[['Date',code+'-u'+ptype[0].lower(),code+'-d'+ptype[0].lower()]].groupby('Date').max(),height=400, widths=180, autosize_mode='none')
widgets = pn.WidgetBox(label, ptype, width=170)
pn.Row(widgets, create_figure, create_table)
import json
with open('countries.json') as f:
gj = json.load(f)
df = pd.DataFrame(ds.groupby('Country').sum()['Daily User Installs'])
color_scale = branca.colormap.linear.viridis.scale(0,20)
map_dict = df.to_dict()
def get_count(ISO_A2,ADMIN):
value = map_dict['Daily User Installs'].get(ISO_A2)
if value is None:
return ADMIN+" : No install"
else:
return ADMIN+" : "+str(value)
for i in range(len(gj['features'])):
gj['features'][i]['properties']['INSTALL'] = get_count(gj['features'][i]['properties']['ISO_A2'],gj['features'][i]['properties']['ADMIN'])
def get_color(feature):
value = map_dict['Daily User Installs'].get(feature['properties']['ISO_A2'])
if value is None:
return 'white' # MISSING -> white
else:
#print(feature['properties']['ADMIN']+' : '+str(value))
return color_scale(value)
m = folium.Map(
location = [0, 0],
tiles="cartodbpositron",
zoom_start = 2
)
folium.GeoJson(
data = gj,
popup=folium.GeoJsonPopup(fields=['INSTALL']),
style_function = lambda feature: {
'fillColor': get_color(feature),
'fillOpacity': 0.7,
'color' : 'None',
'weight' : 1,
}
).add_to(m)
m.add_child(color_scale)
m